#include <SPI.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>  // 添加XPT2046触摸屏库
#include "relax.h"                // 包含位图声明的头文件
#include "move.h"
#include "sleep.h"                // 添加sleep动画头文件
#include <WiFi.h>
#include <time.h>
#include "ESP32Time.h"  // 添加ESP32Time库

// 创建RTC对象
ESP32Time rtc;

// WiFi配置
const char* ssid = "CMCC-yH5f";     // WiFi名称
const char* password = "2x39xh6h";  // WiFi密码

// 屏幕布局配置 - 严格区域分离
#define UI_HEIGHT 60       // UI区域高度（屏幕底部）
#define STATUS_HEIGHT 30   // 状态区域高度（屏幕顶部）
#define BUTTON_WIDTH 60    // 按钮宽度
#define BUTTON_HEIGHT 30   // 按钮高度
#define BUTTON_SPACING 10  // 按钮间距

// 时间显示配置
#define TIME_WIDTH 144    // 时间显示区域宽度 (12 * 6 * 2)
#define TIME_HEIGHT 55    // 时间显示区域高度（增加高度以适应更大的字体）
#define TIME_Y_POS (STATUS_HEIGHT + 10)  // 时间显示在状态栏下方10像素处

// WiFi连接超时设置
const int WIFI_TIMEOUT = 10000;  // WiFi连接超时时间（毫秒）
unsigned long wifiStartTime = 0;  // WiFi开始连接的时间
bool wifiConnecting = false;     // WiFi是否正在连接

// NTP服务器配置
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 8 * 3600;  // 中国时区 UTC+8
const int   daylightOffset_sec = 0;

// 时间变量
struct tm timeinfo;
bool timeInitialized = false;
unsigned long lastTimeUpdate = 0;
const int TIME_UPDATE_INTERVAL = 1000;  // 时间更新间隔（毫秒）
char timeStr[9] = "00:00:00";  // 存储时间字符串
char dateStr[11] = "2024/01/01";  // 存储日期字符串
char lastTimeStr[9] = "00:00:00";  // 存储上一次显示的时间
char lastDateStr[11] = "2024/01/01";  // 存储上一次显示的日期

// 按钮结构体定义
typedef struct {
  int x, y;                 // 按钮位置
  int width, height;        // 按钮大小
  const char* label;        // 按钮文本
  bool pressed;            // 按钮状态
} Button;

// 按钮实例声明
Button feedButton, playButton, cleanButton;

// 动画状态枚举
enum AnimationState {
  ANIM_MOVE,
  ANIM_RELAX,
  ANIM_SLEEP
};

// 当前动画状态
static AnimationState currentAnimation = ANIM_RELAX;

// 颜色定义
#define BG_COLOR TFT_WHITE           // 背景色
#define TEXT_COLOR TFT_BLACK         // 文本颜色
#define TITLE_COLOR TFT_NAVY         // 标题颜色
#define BORDER_COLOR TFT_NAVY        // 边框颜色（深蓝色）
#define BUTTON_BG 0x24DD            // 按钮背景色 (蓝色)
#define BUTTON_ACTIVE 0x1C75        // 按钮激活色 (深蓝色)
#define BUTTON_TEXT TFT_WHITE       // 按钮文本颜色
#define STATUS_BG TFT_LIGHTGREY     // 状态栏背景色
#define UI_BG 0xDEDB               // UI背景色（浅灰色）
#define UI_BORDER TFT_WHITE        // UI边框颜色

// 动画配置
#define MOVE_FRAME_DELAY 150        // move动画帧延迟时间（毫秒）
#define RELAX_FRAME_DELAY 300       // relax动画帧延迟时间（毫秒）
#define SLEEP_FRAME_DELAY 300       // sleep动画帧延迟时间（毫秒）

TFT_eSPI tft = TFT_eSPI();  // 使用 TFT_eSPI 默认配置

// 屏幕缓冲区
static uint16_t* screenBuffer = NULL;      // 当前帧缓冲区
static uint16_t* previousBuffer = NULL;    // 上一帧缓冲区
static bool bufferInitialized = false;     // 缓冲区初始化标志

// 初始化屏幕缓冲区
void initScreenBuffers() {
  if (!bufferInitialized) {
    // 为整个屏幕分配缓冲区
    int screenSize = tft.width() * tft.height();
    screenBuffer = (uint16_t*)malloc(screenSize * sizeof(uint16_t));
    previousBuffer = (uint16_t*)malloc(screenSize * sizeof(uint16_t));
    
    if (screenBuffer && previousBuffer) {
      // 初始化缓冲区为背景色
      for (int i = 0; i < screenSize; i++) {
        screenBuffer[i] = BG_COLOR;
        previousBuffer[i] = BG_COLOR;
      }
      bufferInitialized = true;
    }
  }
}

// 释放屏幕缓冲区
void freeScreenBuffers() {
  if (screenBuffer) {
    free(screenBuffer);
    screenBuffer = NULL;
  }
  if (previousBuffer) {
    free(previousBuffer);
    previousBuffer = NULL;
  }
  bufferInitialized = false;
}

// 将像素写入缓冲区
void drawPixelToBuffer(int16_t x, int16_t y, uint16_t color) {
  if (x >= 0 && x < tft.width() && y >= 0 && y < tft.height() && bufferInitialized) {
    screenBuffer[y * tft.width() + x] = color;
  }
}

// 将水平线写入缓冲区
void drawHLineToBuffer(int16_t x, int16_t y, int16_t w, uint16_t color) {
  for (int16_t i = 0; i < w; i++) {
    drawPixelToBuffer(x + i, y, color);
  }
}

// 将矩形写入缓冲区
void fillRectToBuffer(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
  for (int16_t i = 0; i < h; i++) {
    drawHLineToBuffer(x, y + i, w, color);
  }
}

// 更新屏幕，只更新发生变化的行
void updateScreen() {
  if (!bufferInitialized) return;
  
  int width = tft.width();
  int height = tft.height();
  bool lineChanged = false;
  int startY = -1;
  int lineCount = 0;
  
  // 逐行检查变化
  for (int y = 0; y < height; y++) {
    lineChanged = false;
    int lineOffset = y * width;
    
    // 检查这一行是否有变化
    for (int x = 0; x < width; x++) {
      if (screenBuffer[lineOffset + x] != previousBuffer[lineOffset + x]) {
        lineChanged = true;
        break;
      }
    }
    
    // 如果这一行有变化
    if (lineChanged) {
      if (startY == -1) {
        startY = y;
        lineCount = 1;
      } else {
        lineCount++;
      }
      
      // 复制这一行到上一帧缓冲区
      memcpy(&previousBuffer[lineOffset], &screenBuffer[lineOffset], width * sizeof(uint16_t));
    } else if (startY != -1) {
      // 如果遇到没有变化的行，且之前有变化的行，就更新这些行
      tft.setAddrWindow(0, startY, width, lineCount);
      tft.pushColors(&previousBuffer[startY * width], width * lineCount, true);
      startY = -1;
    }
  }
  
  // 处理最后一组变化的行
  if (startY != -1) {
    tft.setAddrWindow(0, startY, width, lineCount);
    tft.pushColors(&previousBuffer[startY * width], width * lineCount, true);
  }
}

// 触摸屏设置 - 根据实际硬件连接更新
#define TOUCH_CS_PIN 33   // TP_CS IO33 电阻触摸屏片选控制信号
#define TOUCH_IRQ_PIN 36  // TP_IRQ IO36 电阻触摸屏触摸中断信号
// 其他触摸屏引脚 - 记录但不需要在XPT2046_Touchscreen库中直接设置
// TP_SCK IO25 电阻触摸屏SPI总线时钟信号
// TP_DIN IO32 电阻触摸屏SPI总线写数据信号
// TP_DOUT IO39 电阻触摸屏SPI总线读数据信号

// 创建触摸屏对象 - 使用自定义SPI引脚
SPIClass touchSPI(HSPI);                                 // 使用ESP32的HSPI接口
XPT2046_Touchscreen touch(TOUCH_CS_PIN, TOUCH_IRQ_PIN);  // 基本配置

// 触摸屏状态
#define TOUCH_STATUS_ICON_X 230   // 触摸状态图标X坐标 - 移到右上角
#define TOUCH_STATUS_ICON_Y 5     // 触摸状态图标Y坐标
#define TOUCH_STATUS_ICON_SIZE 4  // 触摸状态图标大小 - 减小尺寸
bool show_touch_icon = false;     // 默认隐藏触摸状态图标

// 触摸校准参数 - 初始默认值，将通过校准更新
int touch_min_x = 300;
int touch_max_x = 3800;
int touch_min_y = 300;
int touch_max_y = 3800;
bool touch_calibrated = false;   // 标记是否已校准
bool touch_enabled = true;       // 触摸功能开关
bool touch_initialized = false;  // 触摸初始化状态
bool touch_test_mode = false;    // 触摸测试模式

// 触摸检测优化
#define TOUCH_INTERVAL 50          // 触摸检测间隔(毫秒)
unsigned long lastTouchCheck = 0;  // 上次触摸检测时间

#define RELAX_WIDTH 148
#define RELAX_HEIGHT 190
#define MOVE_WIDTH 146
#define MOVE_HEIGHT 189
#define SLEEP_WIDTH 194
#define SLEEP_HEIGHT 129

// 动画状态
bool isPlayingMoveAnimation = false;  // 保留这个变量以保持兼容性

// SKD动画配置
const float SCALE_FACTOR = 0.7;                     // 缩放倍数

// 变量在setup中计算，基于屏幕实际尺寸
int X_POS = 0;  // X坐标位置将在setup中计算
int Y_POS = 0;  // Y坐标位置将在setup中计算

// 宠物状态
int hunger = 100;                         // 饥饿度 (0-100)
int happiness = 150;                      // 开心度 (0-150)
int cleanliness = 200;                    // 清洁度 (0-200)
unsigned long lastStatusUpdate = 0;       // 上次状态更新时间
const int STATUS_UPDATE_INTERVAL = 1000;  // 状态更新间隔(毫秒)，1秒

// 添加恢复模式标志
bool isRecoveryMode = false;             // 是否处于恢复模式

// 状态变化标志，用于决定是否需要重绘UI
bool uiNeedsUpdate = true;          // 初始化时需要绘制UI
bool statusNeedsUpdate = true;      // 初始化时需要绘制状态栏
int lastHunger = hunger;            // 上次的饥饿度
int lastHappiness = happiness;      // 上次的开心度
int lastCleanliness = cleanliness;  // 上次的清洁度

// 优化显示设置
#define USE_DMA     // 使用DMA加速
#define USE_HW_SPI  // 使用硬件SPI优化

// 高效刷新策略
#define CHUNK_SIZE 8  // 块大小，用于块刷新

// 屏幕旋转设置 (0-3)
int screenRotation = 0;  // 默认为竖向

// SPI设置 - ESP32具体值
#define SPI_FREQUENCY 80000000  // 设置SPI频率为80MHz

// 自定义min函数，解决类型问题
template<class T>
T my_min(T a, T b) {
  return (a < b) ? a : b;
}

// 用于存储帧计算的变量
int currentFrame = 0;
int previousFrame = -1;
unsigned long lastFrameTime = 0;
bool frameNeedsUpdate = true;

// 用于优化绘制的变量
uint16_t* frameChangeMap = NULL;   // 用于记录每个块是否有变化
const uint16_t* prevFrame = NULL;  // 上一帧的引用

#define MAX_FRAME_WIDTH 148   // 使用最大的帧宽度
#define MAX_FRAME_HEIGHT 190  // 使用最大的帧高度

// 定义帧缓冲区大小
#define FRAME_BUFFER_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT)

// 帧缓冲区
static uint16_t* frameBuffer = NULL;
static uint16_t* prevFrameBuffer = NULL;

// 缓冲区声明
uint16_t* scaledBuffer = NULL;

// 初始化帧缓冲区
void initFrameBuffers() {
  if (frameBuffer == NULL) {
    frameBuffer = (uint16_t*)malloc(FRAME_BUFFER_SIZE * sizeof(uint16_t));
  }
  if (prevFrameBuffer == NULL) {
    prevFrameBuffer = (uint16_t*)malloc(FRAME_BUFFER_SIZE * sizeof(uint16_t));
  }
  // 初始化为背景色
  if (frameBuffer && prevFrameBuffer) {
    for (int i = 0; i < FRAME_BUFFER_SIZE; i++) {
      frameBuffer[i] = BG_COLOR;
      prevFrameBuffer[i] = BG_COLOR;
    }
  }
}

// 释放帧缓冲区
void freeFrameBuffers() {
  if (frameBuffer) {
    free(frameBuffer);
    frameBuffer = NULL;
  }
  if (prevFrameBuffer) {
    free(prevFrameBuffer);
    prevFrameBuffer = NULL;
  }
}

// 函数声明区
void switchAnimation(AnimationState newState);              // 动画切换函数
void drawText(const char* text, int x, int y, uint16_t color);
void updateAnimation();
void drawAnimationFrame(int frameIndex, int x, int y, float scale);
void setupDisplay();
void optimizeSPI();
void checkSerialCommand();
void setRotation(int rotation);
void initChangeMap();
void freeChangeMap();
void drawUI();
void drawStatusBars();
void updatePetStatus();
void initButtons();
void drawButton(Button* btn);
void handleButtons();
void feedPet();
void playWithPet();
void cleanPet();
void drawScreenLayout();
bool checkTouch();                                          // 触摸检测函数
bool isTouchInButton(Button* btn, int16_t x, int16_t y);    // 按钮触摸检测函数
void calibrateTouch();                                      // 触摸校准函数
void mapTouchToScreen(TS_Point p, int16_t* x, int16_t* y);  // 触摸坐标映射函数
void drawTouchStatusIcon();                                 // 触摸状态图标绘制函数
bool initTouchScreen();                                     // 触摸屏初始化函数
void testTouchScreen();                                     // 触摸屏测试函数

void cleanup() {
  if (scaledBuffer) {
    free(scaledBuffer);
    scaledBuffer = NULL;
  }
  freeFrameBuffers();
  freeChangeMap();
  freeScreenBuffers(); // 在清理时释放屏幕缓冲区
}

void setup() {
  // 初始化串口
  Serial.begin(115200);

  // 设置默认时间
  struct tm tm;
  tm.tm_year = 2024 - 1900;  // 年份从1900年开始计算
  tm.tm_mon = 0;             // 月份从0开始（0-11）
  tm.tm_mday = 1;            // 日期
  tm.tm_hour = 0;
  tm.tm_min = 0;
  tm.tm_sec = 0;
  time_t t = mktime(&tm);
  struct timeval now = { .tv_sec = t };
  settimeofday(&now, NULL);

  // 分配缩放缓冲区
  int maxWidth = max(MOVE_WIDTH, max(RELAX_WIDTH, SLEEP_WIDTH));
  int maxHeight = max(MOVE_HEIGHT, max(RELAX_HEIGHT, SLEEP_HEIGHT));
  // 直接使用较小的缓冲区大小
  int maxScaledSize = (int)(maxWidth * maxHeight * SCALE_FACTOR);
  
  Serial.print("最大缓冲区大小: ");
  Serial.println(maxScaledSize);
  
  if (scaledBuffer) free(scaledBuffer);
  if (prevFrameBuffer) free(prevFrameBuffer);
  
  // 使用psram分配内存
  scaledBuffer = (uint16_t*)ps_malloc(maxScaledSize * sizeof(uint16_t));
  if (!scaledBuffer) {
    // 如果psram分配失败，尝试使用普通内存
    scaledBuffer = (uint16_t*)malloc(maxScaledSize * sizeof(uint16_t));
  }
  
  prevFrameBuffer = (uint16_t*)ps_malloc(maxScaledSize * sizeof(uint16_t));
  if (!prevFrameBuffer) {
    // 如果psram分配失败，尝试使用普通内存
    prevFrameBuffer = (uint16_t*)malloc(maxScaledSize * sizeof(uint16_t));
  }
  
  if (!scaledBuffer || !prevFrameBuffer) {
    Serial.println("缓冲区分配失败，尝试较小的缓冲区");
    // 如果分配失败，尝试使用更小的缓冲区
    maxScaledSize = (int)(maxWidth * maxHeight * SCALE_FACTOR * 0.75);
    
    if (scaledBuffer) free(scaledBuffer);
    if (prevFrameBuffer) free(prevFrameBuffer);
    
    scaledBuffer = (uint16_t*)malloc(maxScaledSize * sizeof(uint16_t));
    prevFrameBuffer = (uint16_t*)malloc(maxScaledSize * sizeof(uint16_t));
    
    if (!scaledBuffer || !prevFrameBuffer) {
      Serial.println("缓冲区分配仍然失败!");
      return;
    }
  }

  Serial.println("缓冲区分配成功!");

  // 初始化屏幕和优化设置
  setupDisplay();

  // 显示启动信息
  tft.setTextSize(1);
  drawText("Lisa Animation By Fairytale", (tft.width() - 12 * 11) / 2, STATUS_HEIGHT / 2 - 4, TEXT_COLOR);  // 居中显示标题
  delay(200);

  // 初始化变化映射表
  initChangeMap();

  // 初始化帧缓冲区
  initFrameBuffers();

  // 初始化屏幕缓冲区
  initScreenBuffers();

  // 初始化按钮
  initButtons();

  // 绘制屏幕布局
  drawScreenLayout();

  // 绘制UI
  drawUI();

  // 绘制状态栏
  drawStatusBars();

  // 重置动画计时器
  lastFrameTime = millis();
  lastStatusUpdate = millis();
  lastTouchCheck = millis();  // 初始化触摸检测计时器

  // 计算动画位置
  if (currentAnimation == ANIM_SLEEP) {
    // 计算sleep动画的中心位置
    X_POS = (tft.width() - SLEEP_WIDTH * SCALE_FACTOR) / 2;
    Y_POS = STATUS_HEIGHT + TIME_Y_POS + 60;  // 下移到与switchAnimation一致
  } else if (isPlayingMoveAnimation) {
    // 计算move动画的中心位置
    X_POS = (tft.width() - MOVE_WIDTH * SCALE_FACTOR) / 2;
    Y_POS = STATUS_HEIGHT + TIME_Y_POS + 40;  // 下移到与switchAnimation一致
  } else {
    // 计算relax动画的中心位置
    X_POS = (tft.width() - RELAX_WIDTH * SCALE_FACTOR) / 2;
    Y_POS = STATUS_HEIGHT + TIME_Y_POS + 40;  // 下移到与switchAnimation一致
  }

  // 打印帮助信息
  Serial.println("\nRotation control commands: r0-r3");
  Serial.println("Pet control: f=feed, p=play, c=clean");
  Serial.println("Touch screen: enabled, send 'tc' to calibrate, 'td' to disable/enable");

  // 开始WiFi连接（非阻塞，移到最后）
  connectToWiFi();
}

// 绘制屏幕布局
void drawScreenLayout() {
  // 清除屏幕
  tft.fillScreen(BG_COLOR);

  // 绘制顶部分隔线
  for (int i = 0; i < 3; i++) {
    tft.drawFastHLine(0, STATUS_HEIGHT + 7 - i, tft.width(), BORDER_COLOR);
  }

  // 绘制底部分隔线和白线
  for (int i = 0; i < 3; i++) {
    // 绘制深蓝色分隔线
    tft.drawFastHLine(0, tft.height() - UI_HEIGHT + i, tft.width(), BORDER_COLOR);
    // 在深蓝色分隔线下方绘制白线
    tft.drawFastHLine(0, tft.height() - UI_HEIGHT + i + 3, tft.width(), TFT_WHITE);
  }

  // 绘制左侧装饰线
  for (int i = 0; i < 2; i++) {
    tft.drawFastVLine(5 + i, STATUS_HEIGHT + 10, tft.height() - UI_HEIGHT - STATUS_HEIGHT - 20, TFT_NAVY);
  }

  // 绘制右侧装饰线
  for (int i = 0; i < 2; i++) {
    tft.drawFastVLine(tft.width() - 7 + i, STATUS_HEIGHT + 10, tft.height() - UI_HEIGHT - STATUS_HEIGHT - 20, TFT_NAVY);
  }

  // 绘制圆角边框
  tft.drawRoundRect(2, 2, tft.width() - 4, tft.height() - 4, 5, BORDER_COLOR);
}

// 初始化按钮
void initButtons() {
  int buttonY = tft.height() - UI_HEIGHT + (UI_HEIGHT - BUTTON_HEIGHT) / 2;
  int totalButtonWidth = 3 * BUTTON_WIDTH + 2 * BUTTON_SPACING;
  int startX = (tft.width() - totalButtonWidth) / 2;

  // 喂食按钮
  feedButton.x = startX;
  feedButton.y = buttonY;
  feedButton.width = BUTTON_WIDTH;
  feedButton.height = BUTTON_HEIGHT;
  feedButton.label = "Feed";
  feedButton.pressed = false;

  // 玩耍按钮
  playButton.x = startX + BUTTON_WIDTH + BUTTON_SPACING;
  playButton.y = buttonY;
  playButton.width = BUTTON_WIDTH;
  playButton.height = BUTTON_HEIGHT;
  playButton.label = "Play";
  playButton.pressed = false;

  // 清洁按钮
  cleanButton.x = startX + 2 * (BUTTON_WIDTH + BUTTON_SPACING);
  cleanButton.y = buttonY;
  cleanButton.width = BUTTON_WIDTH;
  cleanButton.height = BUTTON_HEIGHT;
  cleanButton.label = "Clean";
  cleanButton.pressed = false;
}

// 初始化变化映射表
void initChangeMap() {
  // 计算需要多少个块
  int blocksX = (MAX_FRAME_WIDTH + CHUNK_SIZE - 1) / CHUNK_SIZE;
  int blocksY = (MAX_FRAME_HEIGHT + CHUNK_SIZE - 1) / CHUNK_SIZE;
  int totalBlocks = blocksX * blocksY;

  // 分配变化映射表内存
  if (frameChangeMap) {
    free(frameChangeMap);
  }

  frameChangeMap = (uint16_t*)malloc(totalBlocks * sizeof(uint16_t));

  if (frameChangeMap) {
    // 初始化所有块为"需要更新"
    for (int i = 0; i < totalBlocks; i++) {
      frameChangeMap[i] = 1;
    }
  }
}

// 释放变化映射表 - 如果还不存在这个函数
void freeChangeMap() {
  if (frameChangeMap) {
    free(frameChangeMap);
    frameChangeMap = NULL;
  }
}

// 主循环
void loop() {
  // 检查WiFi连接状态
  checkWiFiStatus();

  // 检查是否有串口命令
  checkSerialCommand();

  // 如果处于触摸测试模式，执行测试
  if (touch_test_mode) {
    testTouchScreen();
    return;  // 跳过正常的循环处理
  }

  // 检查是否应该更新时间显示
  unsigned long currentMillis = millis();
  if (currentMillis - lastTimeUpdate >= TIME_UPDATE_INTERVAL) {
    lastTimeUpdate = currentMillis;
    drawTime();
  }

  // 检查是否应该更新动画
  updateAnimation();

  // 检查按钮输入 - 包括触摸和串口
  handleButtons();

  // 更新宠物状态
  updatePetStatus();

  // 如果UI需要更新，则重绘UI
  if (uiNeedsUpdate) {
    drawUI();
    uiNeedsUpdate = false;
  }

  // 如果状态栏需要更新，则重绘状态栏
  if (statusNeedsUpdate) {
    drawStatusBars();
    statusNeedsUpdate = false;
  }

  // 在所有绘制完成后更新屏幕
  updateScreen();

  // 添加短暂延迟以减少CPU负载
  yield();
}

// 更新宠物状态
void updatePetStatus() {
  unsigned long currentTime = millis();
  if (currentTime - lastStatusUpdate >= STATUS_UPDATE_INTERVAL) {
    lastStatusUpdate = currentTime;
    
    // 检查是否需要进入恢复模式
    if (!isRecoveryMode && (hunger <= 0 || happiness <= 0 || cleanliness <= 0)) {
      isRecoveryMode = true;
      switchAnimation(ANIM_SLEEP);  // 切换到睡眠动画
    }
    
    if (isRecoveryMode) {
      // 恢复模式：每秒恢复2点
      hunger = min(100, hunger + 2);
      happiness = min(150, happiness + 2);
      cleanliness = min(200, cleanliness + 2);
      
      // 检查是否所有状态都恢复到最大值
      if (hunger >= 100 && happiness >= 150 && cleanliness >= 200) {
        isRecoveryMode = false;
        switchAnimation(ANIM_RELAX);  // 恢复完成，切换到放松动画
      }
    } else {
      // 正常模式：每秒减少1点
      hunger = max(0, hunger - 1);
      happiness = max(0, happiness - 1);
      cleanliness = max(0, cleanliness - 1);
    }
    
    // 检查是否需要更新状态栏
    if (hunger != lastHunger || happiness != lastHappiness || cleanliness != lastCleanliness) {
      statusNeedsUpdate = true;
      lastHunger = hunger;
      lastHappiness = happiness;
      lastCleanliness = cleanliness;
    }
  }
}

// 绘制状态栏
void drawStatusBars() {
  // 只清除状态栏区域
  tft.fillRect(0, 0, tft.width(), STATUS_HEIGHT, BG_COLOR);

  // 重绘分隔线 - 使用渐变效果，向下移动7像素
  for (int i = 0; i < 3; i++) {
    tft.drawFastHLine(0, STATUS_HEIGHT + 7 - i, tft.width(), BORDER_COLOR);
  }

  // 绘制状态指示器的位置和尺寸
  int barWidth = 60;              // 状态条长度
  int barHeight = 8;              // 稍微增加高度
  int startX = tft.width() - 70;  // 进度条靠右显示
  int startY = 5;
  int spacing = 10;      // 增加间距
  int cornerRadius = 2;  // 圆角半径

  // 计算标题位置使其垂直居中
  // 状态栏总高度为STATUS_HEIGHT (30)
  // 三个进度条加间距总高度为 barHeight * 3 + spacing * 2 = 24 + 20 = 44
  tft.setTextSize(3);  // 增大字体尺寸
  int titleHeight = 8 * 3;  // 字体高度 (基础高度8像素 * 字体大小3)
  int titleY = (STATUS_HEIGHT - titleHeight) / 2 + 5;  // 垂直居中并向下移动5像素
  drawText("LISA", 5, titleY, TITLE_COLOR);
  tft.setTextSize(1);  // 恢复正常字体大小

  // 绘制触摸状态图标 - 只在启用时显示
  if (show_touch_icon) {
    drawTouchStatusIcon();
  }

  // 绘制饥饿度 - 最大值100
  tft.fillRoundRect(startX, startY, barWidth, barHeight, cornerRadius, STATUS_BG);
  tft.drawRoundRect(startX, startY, barWidth, barHeight, cornerRadius, BORDER_COLOR);
  if (hunger > 0) {
    int fillWidth = (hunger * (barWidth - 2)) / 100;
    tft.fillRoundRect(startX + 1, startY + 1, fillWidth, barHeight - 2, cornerRadius, TFT_GREEN);
  }
  drawText("HUN", startX - 30, startY + 1, TEXT_COLOR);

  // 绘制开心度 - 最大值150
  tft.fillRoundRect(startX, startY + spacing, barWidth, barHeight, cornerRadius, STATUS_BG);
  tft.drawRoundRect(startX, startY + spacing, barWidth, barHeight, cornerRadius, BORDER_COLOR);
  if (happiness > 0) {
    int fillWidth = (happiness * (barWidth - 2)) / 150;
    tft.fillRoundRect(startX + 1, startY + spacing + 1, fillWidth, barHeight - 2, cornerRadius, TFT_YELLOW);
  }
  drawText("HAP", startX - 30, startY + spacing + 1, TEXT_COLOR);

  // 绘制清洁度 - 最大值200
  tft.fillRoundRect(startX, startY + 2 * spacing, barWidth, barHeight, cornerRadius, STATUS_BG);
  tft.drawRoundRect(startX, startY + 2 * spacing, barWidth, barHeight, cornerRadius, BORDER_COLOR);
  if (cleanliness > 0) {
    int fillWidth = (cleanliness * (barWidth - 2)) / 200;
    tft.fillRoundRect(startX + 1, startY + 2 * spacing + 1, fillWidth, barHeight - 2, cornerRadius, TFT_CYAN);
  }
  drawText("CLN", startX - 30, startY + 2 * spacing + 1, TEXT_COLOR);
}

// 绘制触摸状态图标 - 更小更精致的版本
void drawTouchStatusIcon() {
  uint16_t iconColor;

  // 根据触摸屏状态选择图标颜色
  if (!touch_initialized) {
    iconColor = TFT_RED;  // 未初始化
  } else if (!touch_enabled) {
    iconColor = TFT_ORANGE;  // 已禁用
  } else if (touch_calibrated) {
    iconColor = TFT_GREEN;  // 已校准
  } else {
    iconColor = TFT_BLUE;  // 未校准
  }

  // 绘制触摸图标 - 更小更精致
  tft.fillCircle(TOUCH_STATUS_ICON_X, TOUCH_STATUS_ICON_Y, TOUCH_STATUS_ICON_SIZE / 2, iconColor);
  tft.drawCircle(TOUCH_STATUS_ICON_X, TOUCH_STATUS_ICON_Y, TOUCH_STATUS_ICON_SIZE / 2, TFT_WHITE);
}

// 处理按钮输入
void handleButtons() {
  // 检查触摸输入 - 只在启用触摸功能且初始化成功时检查
  if (touch_enabled && touch_initialized) {
    // 限制触摸检测频率，避免影响动画
    if (millis() - lastTouchCheck >= TOUCH_INTERVAL) {
      checkTouch();
      lastTouchCheck = millis();
    }
  }

  // 处理串口按钮命令
  if (Serial.available() > 0) {
    char cmd = Serial.read();
    switch (cmd) {
      case 'f':  // 喂食命令
        feedPet();
        break;
      case 'p':  // 玩耍命令
        playWithPet();
        break;
      case 'c':  // 清洁命令
        cleanPet();
        break;
      case 't':  // 触摸屏命令前缀
        if (Serial.available() > 0) {
          char subcmd = Serial.read();
          if (subcmd == 'c') {  // 触摸屏校准
            calibrateTouch();
          } else if (subcmd == 'd') {  // 触摸屏开关
            touch_enabled = !touch_enabled;
            Serial.print("触摸屏 ");
            Serial.println(touch_enabled ? "已启用" : "已禁用");
            statusNeedsUpdate = true;  // 更新状态栏以显示触摸状态
          } else if (subcmd == 'r') {  // 重新初始化触摸屏
            touch_initialized = initTouchScreen();
            statusNeedsUpdate = true;  // 更新状态栏以显示触摸状态
          } else if (subcmd == 't') {  // 触摸屏测试
            enterTouchTestMode();
          } else if (subcmd == 'i') {  // 触摸状态图标开关
            show_touch_icon = !show_touch_icon;
            Serial.print("触摸状态图标 ");
            Serial.println(show_touch_icon ? "已显示" : "已隐藏");
            statusNeedsUpdate = true;  // 更新状态栏
          }
        }
        break;
    }
  }
}

// 喂食
void feedPet() {
  // 如果在恢复模式，任意按钮都可以唤醒
  if (isRecoveryMode) {
    // 将所有状态恢复到一半
    hunger = 50;
    happiness = 75;
    cleanliness = 100;
    isRecoveryMode = false;
    statusNeedsUpdate = true;
    switchAnimation(ANIM_RELAX);  // 切换到relax动画
    return;
  }
  
  // 增加饥饿度，最大100
  hunger = min(100, hunger + 20);
  // 降低清洁度
  cleanliness = max(0, cleanliness - 20);
  statusNeedsUpdate = true;
  switchAnimation(ANIM_RELAX);  // 切换到relax动画
}

// 玩耍
void playWithPet() {
  // 如果在恢复模式，任意按钮都可以唤醒
  if (isRecoveryMode) {
    // 将所有状态恢复到一半
    hunger = 50;
    happiness = 75;
    cleanliness = 100;
    isRecoveryMode = false;
    statusNeedsUpdate = true;
    switchAnimation(ANIM_RELAX);  // 切换到relax动画
    return;
  }
  
  // 增加开心度，最大150
  happiness = min(150, happiness + 20);
  // 降低饥饿度
  hunger = max(0, hunger - 10);
  statusNeedsUpdate = true;
  switchAnimation(ANIM_MOVE);  // 切换到move动画
}

// 清洁
void cleanPet() {
  // 如果在恢复模式，任意按钮都可以唤醒
  if (isRecoveryMode) {
    // 将所有状态恢复到一半
    hunger = 50;
    happiness = 75;
    cleanliness = 100;
    isRecoveryMode = false;
    statusNeedsUpdate = true;
    switchAnimation(ANIM_RELAX);  // 切换到relax动画
    return;
  }
  
  // 增加清洁度，最大200
  cleanliness = min(200, cleanliness + 20);
  // 降低开心度
  happiness = max(0, happiness - 15);
  statusNeedsUpdate = true;
  switchAnimation(ANIM_SLEEP);  // 切换到sleep动画
}

// 绘制按钮
void drawButton(Button* btn) {
  uint16_t color = btn->pressed ? BUTTON_ACTIVE : BUTTON_BG;

  // 使用圆角矩形作为按钮背景
  tft.fillRoundRect(btn->x, btn->y, btn->width, btn->height, 4, color);
  
  // 按钮边框
  tft.drawRoundRect(btn->x, btn->y, btn->width, btn->height, 4, TFT_WHITE);

  // 居中显示文本
  int16_t textWidth = strlen(btn->label) * 6;
  int16_t textX = btn->x + (btn->width - textWidth) / 2;
  int16_t textY = btn->y + (btn->height - 8) / 2;

  // 文本
  tft.setTextColor(BUTTON_TEXT);
  tft.setCursor(textX, textY);
  tft.print(btn->label);
}

// 绘制UI界面
void drawUI() {
  // 先绘制白色边框
  tft.fillRect(0, tft.height() - UI_HEIGHT - 3, tft.width(), UI_HEIGHT + 3, UI_BORDER);
  
  // 绘制粉色背景区域，留出边框
  tft.fillRect(2, tft.height() - UI_HEIGHT - 1, tft.width() - 4, UI_HEIGHT - 1, UI_BG);

  // 绘制深蓝色分隔线（3像素）
  for (int i = 0; i < 3; i++) {
    tft.drawFastHLine(0, tft.height() - UI_HEIGHT - 3 + i, tft.width(), BORDER_COLOR);
  }

  // 绘制按钮
  drawButton(&feedButton);
  drawButton(&playButton);
  drawButton(&cleanButton);

  // 绘制作者署名
  tft.setTextSize(1);
  tft.setTextColor(BORDER_COLOR);  // 使用深蓝色，与分隔线颜色一致
  const char* author = "@Fairytale";
  int16_t textWidth = strlen(author) * 6;
  tft.setCursor(tft.width() - textWidth - 3, tft.height() - 10);
  tft.print(author);
}

// 更新动画 - 仅在需要时更新帧
void updateAnimation() {
  unsigned long currentTime = millis();
  int frameDelay;
  
  // 根据当前动画类型选择对应的延迟时间
  switch (currentAnimation) {
    case ANIM_MOVE:
      frameDelay = MOVE_FRAME_DELAY;
      break;
    case ANIM_RELAX:
      frameDelay = RELAX_FRAME_DELAY;
      break;
    case ANIM_SLEEP:
      frameDelay = SLEEP_FRAME_DELAY;
      break;
    default:
      frameDelay = MOVE_FRAME_DELAY;
  }

  if (currentTime - lastFrameTime >= frameDelay) {
    lastFrameTime = currentTime;
    previousFrame = currentFrame;
    
    // 确保缓冲区已初始化
    if (!scaledBuffer || !prevFrameBuffer) {
      Serial.println("重新初始化动画缓冲区");
      int maxWidth = max(MOVE_WIDTH, max(RELAX_WIDTH, SLEEP_WIDTH));
      int maxHeight = max(MOVE_HEIGHT, max(RELAX_HEIGHT, SLEEP_HEIGHT));
      int maxScaledSize = (int)(maxWidth * maxHeight * SCALE_FACTOR);
      
      if (scaledBuffer) free(scaledBuffer);
      if (prevFrameBuffer) free(prevFrameBuffer);
      
      scaledBuffer = (uint16_t*)malloc(maxScaledSize * sizeof(uint16_t));
      prevFrameBuffer = (uint16_t*)malloc(maxScaledSize * sizeof(uint16_t));
      
      if (!scaledBuffer || !prevFrameBuffer) {
        Serial.println("缓冲区分配失败!");
        return;
      }
      
      Serial.println("缓冲区重新初始化成功!");
    }
    
    switch(currentAnimation) {
      case ANIM_MOVE:
        currentFrame = (currentFrame - 1 + epd_bitmap_move_allArray_LEN) % epd_bitmap_move_allArray_LEN;
        if (scaledBuffer && prevFrameBuffer) {
          const uint16_t* frame = epd_bitmap_move_allArray[currentFrame];
          tft.setSwapBytes(true);
          int destWidth = MOVE_WIDTH * SCALE_FACTOR;
          int destHeight = MOVE_HEIGHT * SCALE_FACTOR;
          int changedPixels = scaleImage(frame, scaledBuffer, prevFrameBuffer, MOVE_WIDTH, MOVE_HEIGHT, SCALE_FACTOR);
          if (changedPixels > 0) {
            updateChangedPixels(destWidth, destHeight);
          }
        }
        break;
        
      case ANIM_RELAX:
        currentFrame = (currentFrame + 1) % epd_bitmap_allArray_LEN;
        if (scaledBuffer && prevFrameBuffer) {
          const uint16_t* frame = epd_bitmap_allArray[currentFrame];
          tft.setSwapBytes(true);
          int destWidth = RELAX_WIDTH * SCALE_FACTOR;
          int destHeight = RELAX_HEIGHT * SCALE_FACTOR;
          int changedPixels = scaleImage(frame, scaledBuffer, prevFrameBuffer, RELAX_WIDTH, RELAX_HEIGHT, SCALE_FACTOR);
          if (changedPixels > 0) {
            updateChangedPixels(destWidth, destHeight);
          }
        }
        break;
        
      case ANIM_SLEEP:
        currentFrame = (currentFrame + 1) % epd_bitmap_allArray_SLEEP_LEN;
        if (scaledBuffer && prevFrameBuffer) {
          const uint16_t* frame = epd_bitmap_allArray_sleep[currentFrame];
          tft.setSwapBytes(true);
          int destWidth = SLEEP_WIDTH * SCALE_FACTOR;
          int destHeight = SLEEP_HEIGHT * SCALE_FACTOR;
          int changedPixels = scaleImage(frame, scaledBuffer, prevFrameBuffer, SLEEP_WIDTH, SLEEP_HEIGHT, SCALE_FACTOR);
          if (changedPixels > 0) {
            updateChangedPixels(destWidth, destHeight);
          }
        }
        break;
    }
    
    frameNeedsUpdate = true;
  }
}

// 辅助函数：更新变化的像素
void updateChangedPixels(int destWidth, int destHeight) {
  // 使用pushImage函数一次性更新整个区域
  tft.pushImage(X_POS, Y_POS, destWidth, destHeight, scaledBuffer);
  // 复制当前帧到上一帧缓冲区
  memcpy(prevFrameBuffer, scaledBuffer, destWidth * destHeight * sizeof(uint16_t));
}

// 切换到新动画
void switchAnimation(AnimationState newState) {
  if (currentAnimation == newState) return;
  
  currentAnimation = newState;
  currentFrame = 0;  // 重置帧计数器
  isPlayingMoveAnimation = (newState == ANIM_MOVE);  // 更新兼容性变量
  
  // 更新动画位置
  switch(newState) {
    case ANIM_MOVE:
      X_POS = (tft.width() - MOVE_WIDTH * SCALE_FACTOR) / 2;
      Y_POS = STATUS_HEIGHT + TIME_Y_POS + 40;  // 下移20像素
      break;
    case ANIM_RELAX:
      X_POS = (tft.width() - RELAX_WIDTH * SCALE_FACTOR) / 2;
      Y_POS = STATUS_HEIGHT + TIME_Y_POS + 40;  // 下移20像素
      break;
    case ANIM_SLEEP:
      X_POS = (tft.width() - SLEEP_WIDTH * SCALE_FACTOR) / 2;
      Y_POS = STATUS_HEIGHT + TIME_Y_POS + 60;  // 下移20像素
      break;
  }
  
  // 清除动画区域时保留装饰线和底部样式
  int clearX = 8;  // 保留左侧装饰线
  int clearY = STATUS_HEIGHT + TIME_Y_POS + 10;
  int clearWidth = tft.width() - 16;  // 保留两侧装饰线
  int clearHeight = tft.height() - UI_HEIGHT - clearY - 3;  // 保留底部UI区域和分隔线
  
  // 清除动画区域
  tft.fillRect(clearX, clearY, clearWidth, clearHeight, BG_COLOR);
  
  // 重新绘制顶部分隔线
  for (int i = 0; i < 3; i++) {
    tft.drawFastHLine(0, STATUS_HEIGHT + 7 - i, tft.width(), BORDER_COLOR);
  }

  // 重新绘制左侧装饰线
  for (int i = 0; i < 2; i++) {
    tft.drawFastVLine(5 + i, STATUS_HEIGHT + 10, tft.height() - UI_HEIGHT - STATUS_HEIGHT - 20, TFT_NAVY);
  }

  // 重新绘制右侧装饰线
  for (int i = 0; i < 2; i++) {
    tft.drawFastVLine(tft.width() - 7 + i, STATUS_HEIGHT + 10, tft.height() - UI_HEIGHT - STATUS_HEIGHT - 20, TFT_NAVY);
  }
  
  // 重新绘制底部UI
  drawUI();
}

// 优化的绘制动画帧函数
void drawAnimationFrame(int frameIndex, int x, int y, float scale) {
  const uint16_t* frame = NULL;
  int srcWidth = 0;
  int srcHeight = 0;
  
  // 根据当前动画状态选择对应的帧和尺寸
  switch(currentAnimation) {
    case ANIM_MOVE:
      frame = epd_bitmap_move_allArray[frameIndex];
      srcWidth = MOVE_WIDTH;
      srcHeight = MOVE_HEIGHT;
      break;
    case ANIM_RELAX:
      frame = epd_bitmap_allArray[frameIndex];
      srcWidth = RELAX_WIDTH;
      srcHeight = RELAX_HEIGHT;
      break;
    case ANIM_SLEEP:
      frame = epd_bitmap_allArray_sleep[frameIndex];
      srcWidth = SLEEP_WIDTH;
      srcHeight = SLEEP_HEIGHT;
      break;
  }
  
  // 设置颜色格式为RGB565
  tft.setSwapBytes(true);
  
  if (scaledBuffer && prevFrameBuffer && frame) {
    // 缩放图像并获取变化的像素
    int destWidth = srcWidth * scale;
    int destHeight = srcHeight * scale;
    int changedPixels = scaleImage(frame, scaledBuffer, prevFrameBuffer, srcWidth, srcHeight, scale);
    
    // 如果有像素变化，逐像素更新
    if (changedPixels > 0) {
      for (int y = 0; y < destHeight; y++) {
        for (int x = 0; x < destWidth; x++) {
          int pos = y * destWidth + x;
          if (scaledBuffer[pos] != prevFrameBuffer[pos]) {
            tft.drawPixel(X_POS + x, Y_POS + y, scaledBuffer[pos]);
            prevFrameBuffer[pos] = scaledBuffer[pos];
          }
        }
      }
    }
  }
}

// 检查串口命令
void checkSerialCommand() {
  if (Serial.available() > 0) {
    String command = Serial.readStringUntil('\n');
    command.trim();

    // 旋转命令: r0, r1, r2, r3
    if (command.length() == 2 && command.startsWith("r")) {
      int rotation = command.substring(1).toInt();
      if (rotation >= 0 && rotation <= 3) {
        setRotation(rotation);
      }
    }
    // 触摸屏校准命令: tc
    else if (command == "tc") {
      calibrateTouch();
    }
    // 触摸屏开关命令: td
    else if (command == "td") {
      touch_enabled = !touch_enabled;
      Serial.print("触摸屏 ");
      Serial.println(touch_enabled ? "已启用" : "已禁用");
      statusNeedsUpdate = true;  // 更新状态栏以显示触摸状态
    }
    // 触摸屏重新初始化命令: tr
    else if (command == "tr") {
      touch_initialized = initTouchScreen();
      statusNeedsUpdate = true;  // 更新状态栏以显示触摸状态
    }
    // 触摸屏测试命令: tt
    else if (command == "tt") {
      enterTouchTestMode();
    }
    // 触摸状态图标开关命令: ti
    else if (command == "ti") {
      show_touch_icon = !show_touch_icon;
      Serial.print("触摸状态图标 ");
      Serial.println(show_touch_icon ? "已显示" : "已隐藏");
      statusNeedsUpdate = true;  // 更新状态栏
    }
  }
}

// 设置屏幕旋转并更新显示
void setRotation(int rotation) {
  if (rotation == screenRotation) return;  // 如果旋转值相同，不做任何操作

  screenRotation = rotation;

  // 更新屏幕旋转
  tft.setRotation(screenRotation);

  // 如果触摸屏已初始化，同步更新触摸屏旋转
  if (touch_initialized) {
    touch.setRotation(screenRotation);
  }

  // 重新计算居中位置
  X_POS = (tft.width() - MAX_FRAME_WIDTH) / 2;
  if (X_POS < 0) X_POS = 0;

  // 计算动画区域位置 - 确保在状态栏和UI区域之间
  int availableHeight = tft.height() - UI_HEIGHT - STATUS_HEIGHT;
  Y_POS = STATUS_HEIGHT + (availableHeight - MAX_FRAME_HEIGHT) / 2 + 5;  // 向下移动5像素
  if (Y_POS < STATUS_HEIGHT) Y_POS = STATUS_HEIGHT;

  // 重新初始化按钮
  initButtons();

  // 重绘屏幕布局
  drawScreenLayout();

  // 标记UI和状态栏需要更新
  uiNeedsUpdate = true;
  statusNeedsUpdate = true;

  // 强制立即更新帧
  frameNeedsUpdate = true;
  previousFrame = -1;
  prevFrame = NULL;

  // 重新初始化变化映射表
  initChangeMap();
}

// 设置显示和优化选项
void setupDisplay() {
#ifdef USE_HW_SPI
  // 在初始化屏幕前优化SPI
  optimizeSPI();
#endif

  tft.begin();
  tft.setRotation(screenRotation);  // 使用当前的屏幕旋转值
  tft.fillScreen(BG_COLOR);

  // 设置颜色格式为RGB565
  tft.setSwapBytes(true);

  // 初始化触摸屏
  touch_initialized = initTouchScreen();

  // 计算动画区域位置 - 确保在状态栏和UI区域之间
  X_POS = (tft.width() - MAX_FRAME_WIDTH) / 2;
  if (X_POS < 0) X_POS = 0;

  int availableHeight = tft.height() - UI_HEIGHT - STATUS_HEIGHT;
  Y_POS = STATUS_HEIGHT + TIME_Y_POS + 40;  // 设置初始Y位置与其他位置一致
  if (Y_POS < STATUS_HEIGHT) Y_POS = STATUS_HEIGHT;

#ifdef USE_DMA
  // 启用DMA (如果支持)
  tft.initDMA();
#endif
}

// 优化SPI设置
void optimizeSPI() {
#ifdef ESP32
  // 设置更高的SPI速度
  SPI.begin();  // 使用默认引脚
  SPI.setFrequency(SPI_FREQUENCY);
#else
  // 对于其他平台的优化
  SPI.begin();
  SPI.setFrequency(SPI_FREQUENCY);
#endif
}

// 显示文本
void drawText(const char* text, int x, int y, uint16_t color) {
  // 在TFT屏幕上绘制文本
  tft.setTextColor(color);
  tft.setCursor(x, y);
  tft.print(text);
}

// 检查触摸输入 - 优化版本，减少对动画的影响
bool checkTouch() {
  static uint32_t lastPressTime = 0;
  static bool wasPressed = false;
  bool touched = false;

  // 防止触摸事件过于频繁
  if (millis() - lastPressTime < 300) {
    return false;
  }

  // 检查是否有触摸事件
  if (touch.touched()) {
    // 获取触摸坐标
    TS_Point p = touch.getPoint();

    // 映射触摸坐标到屏幕坐标
    int16_t x, y;
    mapTouchToScreen(p, &x, &y);

    // 只处理UI区域内的触摸，避免干扰动画区域
    if (y >= tft.height() - UI_HEIGHT) {
      // 检查是否点击了按钮
      Button* pressedButton = NULL;

      if (isTouchInButton(&feedButton, x, y)) {
        pressedButton = &feedButton;
        feedPet();
      } else if (isTouchInButton(&playButton, x, y)) {
        pressedButton = &playButton;
        playWithPet();
      } else if (isTouchInButton(&cleanButton, x, y)) {
        pressedButton = &cleanButton;
        cleanPet();
      }

      // 如果点击了按钮，显示按钮按下效果
      if (pressedButton != NULL) {
        // 记录按钮状态
        pressedButton->pressed = true;

        // 立即更新按钮显示
        drawButton(pressedButton);

        // 记录时间和状态
        lastPressTime = millis();
        wasPressed = true;
        touched = true;

        // 延迟一小段时间显示按下效果
        delay(50);

        // 恢复按钮状态
        pressedButton->pressed = false;
        
        // 重新绘制整个UI以保持样式一致
        drawUI();
      }
    }

    // 等待触摸释放
    uint32_t touchReleaseTimeout = millis() + 100;
    while (touch.touched() && millis() < touchReleaseTimeout) {
      delay(5);
    }
  } else if (wasPressed && millis() - lastPressTime > 100) {
    // 重置所有按钮状态
    feedButton.pressed = false;
    playButton.pressed = false;
    cleanButton.pressed = false;
    wasPressed = false;

    // 重新绘制UI以确保样式一致
    drawUI();
  }

  return touched;
}

// 检查触摸点是否在按钮内
bool isTouchInButton(Button* btn, int16_t x, int16_t y) {
  return (x >= btn->x && x <= btn->x + btn->width && y >= btn->y && y <= btn->y + btn->height);
}

// 触摸坐标映射函数
void mapTouchToScreen(TS_Point p, int16_t* x, int16_t* y) {
  // 将触摸坐标映射到屏幕坐标
  *x = map(p.x, touch_min_x, touch_max_x, 0, tft.width());
  *y = map(p.y, touch_min_y, touch_max_y, 0, tft.height());

  // 根据屏幕旋转调整坐标
  if (screenRotation == 1) {
    int16_t temp = *x;
    *x = *y;
    *y = tft.height() - temp;
  } else if (screenRotation == 2) {
    *x = tft.width() - *x;
    *y = tft.height() - *y;
  } else if (screenRotation == 3) {
    int16_t temp = *x;
    *x = tft.width() - *y;
    *y = temp;
  }
}

// 触摸屏校准函数 - 优化版本
void calibrateTouch() {
  Serial.println("开始触摸屏校准...");

  // 检查触摸屏是否已初始化
  if (!touch_initialized) {
    Serial.println("触摸屏未初始化，无法校准");

    // 显示错误信息
    tft.fillScreen(TFT_WHITE);
    tft.setTextSize(2);
    tft.setTextColor(TFT_RED);
    tft.setCursor(20, 30);
    tft.println("触摸屏未初始化");
    tft.setTextSize(1);
    tft.setCursor(20, 60);
    tft.println("请检查硬件连接");
    tft.setCursor(20, 80);
    tft.println("按任意键继续...");

    // 等待用户按键
    while (!Serial.available()) {
      delay(100);
    }

    // 清空串口缓冲区
    while (Serial.available()) {
      Serial.read();
    }

    // 重绘屏幕
    drawScreenLayout();
    uiNeedsUpdate = true;
    statusNeedsUpdate = true;
    return;
  }

  // 暂时禁用触摸功能，避免干扰校准过程
  bool oldTouchEnabled = touch_enabled;
  touch_enabled = false;

  // 清除屏幕
  tft.fillScreen(TFT_WHITE);

  // 显示校准指引
  tft.setTextSize(2);
  tft.setTextColor(TFT_BLACK);
  tft.setCursor(20, 30);
  tft.println("触摸屏校准");
  tft.setTextSize(1);
  tft.setCursor(20, 60);
  tft.println("请依次点击屏幕上的四个角");

  // 校准点坐标 - 略微远离边缘，更容易点击
  int16_t calPoints[4][2] = {
    { 20, 20 },                              // 左上
    { tft.width() - 20, 20 },                // 右上
    { 20, tft.height() - 20 },               // 左下
    { tft.width() - 20, tft.height() - 20 }  // 右下
  };

  // 收集的原始触摸数据
  int16_t rawPoints[4][2];

  // 依次显示并获取校准点
  for (int i = 0; i < 4; i++) {
    // 绘制校准点
    tft.fillScreen(TFT_WHITE);

    // 显示当前点的序号和指示
    tft.setTextSize(1);
    tft.setTextColor(TFT_BLACK);
    tft.setCursor(tft.width() / 2 - 50, 10);
    tft.print("点击第 ");
    tft.print(i + 1);
    tft.print(" 个红点");

    // 绘制目标点 - 使用更明显的标记
    tft.fillCircle(calPoints[i][0], calPoints[i][1], 5, TFT_RED);
    tft.drawCircle(calPoints[i][0], calPoints[i][1], 8, TFT_BLACK);
    tft.drawCircle(calPoints[i][0], calPoints[i][1], 11, TFT_BLACK);

    // 等待触摸
    Serial.print("请点击第 ");
    Serial.print(i + 1);
    Serial.println(" 个点");

    // 等待触摸按下，增加超时处理
    uint32_t touchTimeout = millis() + 10000;  // 10秒超时
    bool touchDetected = false;

    while (!touchDetected && millis() < touchTimeout) {
      if (touch.touched()) {
        touchDetected = true;
      }
      delay(10);
    }

    if (!touchDetected) {
      Serial.println("触摸超时，校准失败");
      break;
    }

    // 获取触摸点 - 获取多次并取平均值，提高准确性
    int32_t sumX = 0, sumY = 0;
    int samples = 8;  // 增加采样次数
    int validSamples = 0;

    for (int s = 0; s < samples; s++) {
      if (touch.touched()) {
        TS_Point p = touch.getPoint();
        // 过滤明显异常值
        if (p.x > 0 && p.y > 0 && p.x < 4096 && p.y < 4096) {
          sumX += p.x;
          sumY += p.y;
          validSamples++;
        }
        delay(10);
      }
    }

    // 确保有足够的有效样本
    if (validSamples < samples / 2) {
      Serial.println("有效样本不足，校准失败");
      i--;  // 重试当前点
      continue;
    }

    rawPoints[i][0] = sumX / validSamples;
    rawPoints[i][1] = sumY / validSamples;

    Serial.print("原始坐标: ");
    Serial.print(rawPoints[i][0]);
    Serial.print(",");
    Serial.println(rawPoints[i][1]);

    // 等待触摸释放，增加超时处理
    touchTimeout = millis() + 5000;  // 5秒超时
    while (touch.touched() && millis() < touchTimeout) {
      delay(10);
    }

    delay(300);  // 等待一段时间再进行下一个点
  }

  // 计算校准参数 - 使用更稳健的方法
  // 对于X坐标，左侧点应该是最小值，右侧点应该是最大值
  int leftX = (rawPoints[0][0] + rawPoints[2][0]) / 2;
  int rightX = (rawPoints[1][0] + rawPoints[3][0]) / 2;

  // 对于Y坐标，上侧点应该是最小值，下侧点应该是最大值
  int topY = (rawPoints[0][1] + rawPoints[1][1]) / 2;
  int bottomY = (rawPoints[2][1] + rawPoints[3][1]) / 2;

  // 检查校准点是否合理
  bool validCalibration = true;

  // 检查X方向
  if (abs(leftX - rightX) < 1000) {
    Serial.println("X方向校准点距离过近，校准失败");
    validCalibration = false;
  }

  // 检查Y方向
  if (abs(topY - bottomY) < 1000) {
    Serial.println("Y方向校准点距离过近，校准失败");
    validCalibration = false;
  }

  // 根据屏幕方向可能需要交换X和Y的最大最小值
  if (leftX > rightX) {
    touch_min_x = rightX;
    touch_max_x = leftX;
  } else {
    touch_min_x = leftX;
    touch_max_x = rightX;
  }

  if (topY > bottomY) {
    touch_min_y = bottomY;
    touch_max_y = topY;
  } else {
    touch_min_y = topY;
    touch_max_y = bottomY;
  }

  // 增加一点余量，确保可以触及屏幕边缘
  int xMargin = (touch_max_x - touch_min_x) * 0.05;
  int yMargin = (touch_max_y - touch_min_y) * 0.05;

  touch_min_x -= xMargin;
  touch_max_x += xMargin;
  touch_min_y -= yMargin;
  touch_max_y += yMargin;

  // 确保范围有效
  if (!validCalibration || touch_max_x - touch_min_x < 1000 || touch_max_y - touch_min_y < 1000) {
    // 校准失败，使用默认值
    touch_min_x = 300;
    touch_max_x = 3800;
    touch_min_y = 300;
    touch_max_y = 3800;

    Serial.println("校准失败，使用默认值");
    touch_calibrated = false;
  } else {
    touch_calibrated = true;
    Serial.println("校准成功！");
  }

  // 打印校准参数
  Serial.print("X范围: ");
  Serial.print(touch_min_x);
  Serial.print(" - ");
  Serial.println(touch_max_x);

  Serial.print("Y范围: ");
  Serial.print(touch_min_y);
  Serial.print(" - ");
  Serial.println(touch_max_y);

  // 显示校准结果
  tft.fillScreen(TFT_WHITE);
  tft.setCursor(20, 30);
  tft.setTextSize(2);
  tft.println(touch_calibrated ? "校准成功!" : "校准失败!");
  tft.setTextSize(1);
  tft.setCursor(20, 60);
  if (touch_calibrated) {
    tft.println("触摸屏已准备就绪");
  } else {
    tft.println("使用默认参数，可能不准确");
    tft.setCursor(20, 80);
    tft.println("请再次尝试校准");
  }
  tft.setCursor(20, 100);
  tft.println("点击屏幕继续...");

  // 等待触摸继续
  delay(1000);  // 先等待一段时间，避免误触

  // 等待触摸或串口输入
  uint32_t continueTimeout = millis() + 10000;  // 10秒超时
  bool continueTouched = false;

  while (!continueTouched && millis() < continueTimeout) {
    if (touch.touched() || Serial.available()) {
      continueTouched = true;
    }
    delay(100);
  }

  // 清空触摸和串口缓冲区
  while (touch.touched()) {
    delay(10);
  }
  while (Serial.available()) {
    Serial.read();
  }

  // 恢复触摸功能状态
  touch_enabled = oldTouchEnabled;

  // 重绘屏幕布局
  drawScreenLayout();

  // 标记UI和状态栏需要更新
  uiNeedsUpdate = true;
  statusNeedsUpdate = true;

  // 强制立即更新帧
  frameNeedsUpdate = true;
  previousFrame = -1;
  prevFrame = NULL;
}

// 初始化触摸屏
bool initTouchScreen() {
  // 配置触摸屏SPI接口
  touchSPI.begin(25, 39, 32, 33);  // SCK, MISO, MOSI, CS

  // 尝试初始化触摸屏 - 使用自定义SPI接口
  bool success = touch.begin(touchSPI);

  if (success) {
    Serial.println("触摸屏初始化成功");
    touch_enabled = true;
    // 设置触摸屏旋转以匹配显示屏
    touch.setRotation(screenRotation);
  } else {
    Serial.println("触摸屏初始化失败");
    touch_enabled = false;
  }

  return success;
}

// 进入触摸测试模式
void enterTouchTestMode() {
  // 检查触摸屏是否已初始化
  if (!touch_initialized) {
    Serial.println("触摸屏未初始化，无法进入测试模式");
    return;
  }

  Serial.println("进入触摸屏测试模式，发送任意字符退出");
  touch_test_mode = true;

  // 准备测试界面
  tft.fillScreen(TFT_WHITE);
  tft.setTextSize(2);
  tft.setTextColor(TFT_BLACK);
  tft.setCursor(20, 20);
  tft.println("触摸屏测试模式");
  tft.setTextSize(1);
  tft.setCursor(20, 50);
  tft.println("点击屏幕任意位置");
  tft.setCursor(20, 70);
  tft.println("发送任意字符退出");

  // 绘制测试区域边框
  tft.drawRect(10, 90, tft.width() - 20, tft.height() - 100, TFT_BLACK);
}

// 触摸屏测试函数
void testTouchScreen() {
  // 检查是否有串口输入，如果有则退出测试模式
  if (Serial.available() > 0) {
    // 清空串口缓冲区
    while (Serial.available()) {
      Serial.read();
    }

    // 退出测试模式
    touch_test_mode = false;
    Serial.println("退出触摸屏测试模式");

    // 重绘屏幕
    drawScreenLayout();
    uiNeedsUpdate = true;
    statusNeedsUpdate = true;
    frameNeedsUpdate = true;
    return;
  }

  // 检查是否有触摸事件
  if (touch.touched()) {
    // 获取触摸坐标
    TS_Point p = touch.getPoint();

    // 获取原始坐标和映射坐标
    int16_t x, y;
    mapTouchToScreen(p, &x, &y);

    // 打印坐标信息
    Serial.print("原始: (");
    Serial.print(p.x);
    Serial.print(",");
    Serial.print(p.y);
    Serial.print(") 映射: (");
    Serial.print(x);
    Serial.print(",");
    Serial.print(y);
    Serial.println(")");

    // 在屏幕上显示触摸点
    // 先清除上次的坐标显示
    tft.fillRect(20, 90, tft.width() - 40, 40, TFT_WHITE);

    // 显示新坐标
    tft.setTextSize(1);
    tft.setTextColor(TFT_BLACK);
    tft.setCursor(20, 100);
    tft.print("原始: (");
    tft.print(p.x);
    tft.print(",");
    tft.print(p.y);
    tft.print(")");

    tft.setCursor(20, 120);
    tft.print("映射: (");
    tft.print(x);
    tft.print(",");
    tft.print(y);
    tft.print(")");

    // 绘制触摸点
    static int lastX = -1, lastY = -1;

    // 擦除上一个点(如果有)
    if (lastX >= 0 && lastY >= 0) {
      tft.fillCircle(lastX, lastY, 5, TFT_WHITE);
      tft.drawCircle(lastX, lastY, 5, TFT_LIGHTGREY);
    }

    // 绘制新的点
    tft.fillCircle(x, y, 5, TFT_RED);
    tft.drawCircle(x, y, 6, TFT_BLACK);

    // 保存当前点坐标
    lastX = x;
    lastY = y;

    // 等待触摸释放
    uint32_t touchReleaseTimeout = millis() + 100;
    while (touch.touched() && millis() < touchReleaseTimeout) {
      delay(5);
    }
  }

  // 短暂延迟，减少CPU负载
  delay(10);
}

// 缩放图像函数，返回变化的像素数量
int scaleImage(const uint16_t* source, uint16_t* dest, uint16_t* prevDest, int srcWidth, int srcHeight, float scale) {
  int destWidth = srcWidth * scale;
  int destHeight = srcHeight * scale;
  int changedPixels = 0;
  
  for (int y = 0; y < destHeight; y++) {
    for (int x = 0; x < destWidth; x++) {
      // 计算源图像中对应的位置
      int srcX = x / scale;
      int srcY = y / scale;
      // 确保不越界
      srcX = min(srcX, srcWidth - 1);
      srcY = min(srcY, srcHeight - 1);
      // 获取新像素值
      uint16_t newPixel = source[srcY * srcWidth + srcX];
      // 计算目标缓冲区位置
      int destPos = y * destWidth + x;
      // 如果像素值发生变化，更新它
      if (prevDest[destPos] != newPixel) {
        dest[destPos] = newPixel;
        changedPixels++;
      } else {
        dest[destPos] = prevDest[destPos];
      }
    }
  }
  return changedPixels;
}

// WiFi连接函数 - 非阻塞版本
void connectToWiFi() {
  Serial.print("正在连接WiFi");
  WiFi.begin(ssid, password);
  wifiStartTime = millis();
  wifiConnecting = true;
}

// 检查WiFi连接状态
void checkWiFiStatus() {
  if (!wifiConnecting) return;
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi连接成功");
    Serial.print("IP地址: ");
    Serial.println(WiFi.localIP());
    wifiConnecting = false;
    syncTime();  // WiFi连接成功后同步时间
  } else if (millis() - wifiStartTime > WIFI_TIMEOUT) {
    Serial.println("\nWiFi连接超时");
    wifiConnecting = false;
  }
}

// 时间同步函数
void syncTime() {
  if (WiFi.status() == WL_CONNECTED) {
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    if (getLocalTime(&timeinfo)) {
      timeInitialized = true;
      Serial.println("时间同步成功");
    } else {
      Serial.println("时间同步失败");
    }
  }
}

// 绘制时间函数
void drawTime() {
  // 获取当前时间
  String timeStr = rtc.getTime();  // 格式: HH:MM:SS
  String dateStr = rtc.getDate();  // 格式: YYYY-MM-DD
  
  // 清除时间显示区域
  int timeX = (tft.width() - TIME_WIDTH) / 2;
  tft.fillRect(timeX - 10, STATUS_HEIGHT + 10, TIME_WIDTH + 20, TIME_HEIGHT, BG_COLOR);

  // 显示时间 - 使用更大的字体和绿色
  tft.setTextSize(3);  // 增大字体
  int timeStrWidth = strlen(timeStr.c_str()) * 18;  // 每个字符宽度18像素，字体大小3
  timeX = (tft.width() - timeStrWidth) / 2;
  drawText(timeStr.c_str(), timeX, STATUS_HEIGHT + 12, TFT_DARKGREEN);  // 使用深绿色显示时间

  // 显示日期
  tft.setTextSize(1);
  int dateStrWidth = strlen(dateStr.c_str()) * 6;  // 每个字符宽度6像素，字体大小1
  int dateX = (tft.width() - dateStrWidth) / 2;
  drawText(dateStr.c_str(), dateX, STATUS_HEIGHT + 42, TFT_DARKGREEN);  // 日期也使用深绿色保持一致

  // 重新绘制左右装饰线
  for (int i = 0; i < 2; i++) {
    tft.drawFastVLine(5 + i, STATUS_HEIGHT + 10, tft.height() - UI_HEIGHT - STATUS_HEIGHT - 20, TFT_NAVY);
    tft.drawFastVLine(tft.width() - 7 + i, STATUS_HEIGHT + 10, tft.height() - UI_HEIGHT - STATUS_HEIGHT - 20, TFT_NAVY);
  }
}
